using AnimCollections;
using System;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;

namespace DA.AnimGraph {
    public struct TransitionEvaluator : IDisposable {
        public int count { get; private set; }
        public bool isInTransition { get; private set; }
        public int newestState => weights[newestStateIndex].Item1;

        public NativeSimpleArray<(int, float)> weights; // state序号,权重
        int writeIndex; // 下一个写入的位置
        int readIndex; // 最旧的一个有效位置
        int newestStateIndex; // 存储新状态的位置，是 writeIndex 的前一个，最新的有效位置

        float duration;
        float alpha;

        public TransitionEvaluator(int capacity, ref GraphBuffer buffer) {
            buffer.MallocNativeSimpleArray(out weights, capacity);
            writeIndex = 0;
            readIndex = 0;
            count = 0;
            newestStateIndex = 0;

            isInTransition = false;
            duration = 0f;
            alpha = 0f;
        }

        public void Dispose() {
            if (weights.IsCreated) {
                weights.Dispose();
            }
        }

        public void SetFirstState(int state) {
            weights[0] = (state, 1);
            count = 1;
            writeIndex = 1;
            readIndex = 0;
            newestStateIndex = 0;
        }

        /// <summary>
        /// 添加新状态
        /// </summary>
        /// <param name="newState"></param>
        /// <param name="inDuration"></param>
        /// <param name="ignoreIfContain">若已经包含则不进入</param>
        /// <returns> 是否成功添加 </returns>
        public bool AddNewState(int newState, float inDuration, bool ignoreIfContain = true) {
            if (newState == weights[newestStateIndex].Item1) return false;
            if (ContainState(newState)) {
                if (ignoreIfContain) {
                    // 若已经包含则不进入
                    return false;
                } else {
                    // 已包含也要重新进入。原来的直接删除，添加为新状态
                    GetEnumerator(out Iter iter);
                    int tmpState = 0;
                    float tmpWeight = 0;
                    float storageWeight = 0; // 原权重交给原当前状态
                    bool isBeforeState = true;
                    while (iter.MoveNext()) {
                        var (thisState, thisWeight) = iter.current;

                        // 排在原位置之前的向后移动，原位置之后的不变
                        if (isBeforeState) {
                            bool currentIsNewState = newState == thisState; // iter.CurrentIsNewState();
                            if (currentIsNewState) {
                                storageWeight = thisWeight;
                                isBeforeState = false;
                            }
                            int currentIndex = iter.currentIndex;
                            weights[currentIndex] = (tmpState, tmpWeight);
                            (tmpState, tmpWeight) = (thisState, thisWeight);
                        }
                    }
                    var oldState = weights[newestStateIndex];
                    oldState.Item2 += storageWeight;
                    weights[newestStateIndex] = oldState;

                    //读位置向后移一个，接下来可以继续走添加流程
                    readIndex = GetNextIndex(readIndex);
                    --count;
                }
            }

            bool isNotFull = count != weights.Length;
            if (isNotFull) {
                weights[writeIndex] = (newState, 0);
                newestStateIndex = writeIndex;

                ++count;
                writeIndex = GetNextIndex(writeIndex);
                isInTransition = true;
                duration = inDuration;
                alpha = 0f;
                return true;
            } else {
                // 容量满了
                // 最旧一个的权重交给第二旧的
                var (_, w) = weights[readIndex];
                readIndex = GetNextIndex(readIndex);
                var last = weights[readIndex];
                last.Item2 += w;
                weights[readIndex] = last;

                weights[writeIndex] = (newState, 0);
                newestStateIndex = writeIndex;

                writeIndex = GetNextIndex(writeIndex);
                isInTransition = true;
                duration = inDuration;
                alpha = 0f;
                return true;
            }
        }

        public void Evaluate(float deltaTime) {
            if (count == 0) return;
            if (!isInTransition) return;

            if (duration == 0) {
                alpha = 1;
                count = 1;
                readIndex = GetNextIndex(writeIndex, -1);
            } else {
                float oldAlpha = alpha;
                alpha += deltaTime / duration; // 可改为用 AlphaFunction 或 AlphaEase
                alpha = math.clamp(alpha, 0, 1);
                var reduceWeight = alpha - oldAlpha;

                GetEnumerator(out Iter iter);
                int popDepth = 0;
                while (iter.MoveNext()) {
                    if (iter.currentIndex != newestStateIndex) {
                        var c = iter.current;
                        var newWeight = c.Item2.Reduce(ref reduceWeight);
                        c.Item2 = newWeight;
                        iter.current = c;
                        if (newWeight == 0) {
                            ++popDepth;
                        }

                        if (reduceWeight == 0) {
                            break;
                        }
                    }
                }
                // 到这里需不需要检查 reduceWeight 是否大于0？正常 reduceWeight 应该是0

                // popDepth 应该 <= count -1
                readIndex = GetNextIndex(readIndex, popDepth);
                count -= popDepth;
            }

            if (alpha.IsNear(1)) {
                alpha = 1;
                isInTransition = false;
            }

            var w = weights[newestStateIndex];
            w.Item2 = alpha;
            weights[newestStateIndex] = w;
        }

        int GetNextIndex(int index, int step = 1) {
            var result = (step + index) % weights.Length;
            if (result < 0) {
                result += weights.Length;
            }
            return result;
        }

        bool ContainState(int state) {
            // 可用iter重写
            bool isFull = count == weights.Length;
            if (isFull) {
                for (int i = 0; i < weights.Length; i++) {
                    if (weights[i].Item1 == state) {
                        return true;
                    }
                }

                return false;
            }

            int index = readIndex;
            while (index != writeIndex) {
                if (weights[index].Item1 == state) {
                    return true;
                }

                index = GetNextIndex(index);
            }

            return false;
        }

        public void GetEnumerator(out Iter iter) {
            iter = new Iter(ref this);
        }


        public unsafe struct Iter {
            private TransitionEvaluator* target;
            public int currentIndex { get; private set; }
            public int iterIndex { get; private set; }

            internal Iter(ref TransitionEvaluator transitionEvaluator) {
                target = (TransitionEvaluator*)UnsafeUtility.AddressOf(ref transitionEvaluator);
                currentIndex = -1;
                iterIndex = 0;
            }

            /// <summary>
            /// 返回值为(port, 权重)
            /// </summary>
            public (int, float) current {
                get => target->weights[currentIndex];
                set => target->weights[currentIndex] = value;
            }

            public bool MoveNext() {
                if (target->count == 0) return false;
                if (currentIndex < 0) {
                    currentIndex = target->readIndex;
                    iterIndex = 0;
                    return true;
                }

                currentIndex = target->GetNextIndex(currentIndex);
                if (currentIndex != target->writeIndex) {
                    ++iterIndex;
                    return true;
                }

                return false;
            }

            /// <summary>
            /// 当前遍历到的是否是最新的一个
            /// </summary>
            public bool CurrentIsNewestState() {
                return currentIndex == target->newestStateIndex;
            }

            public void Reset() {
                currentIndex = -1;
            }
        }
    }
}
